//
// Created by wlk12 on 2023/3/14.
//

#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <functional>
#include <variant>
#include <optional>

class A : public std::enable_shared_from_this<A>
{
public:
    A() {
        n = 4;
    }

    int64_t n = 1;
};


class Base
{
public:
    explicit Base(int n) : n(n) {}
    virtual ~Base() = default;
//    virtual ~Base(){}
    void f() {
        std::cout << "Base" << std::endl;
    }
    int n = 0;
};

class Base2
{
public:
    explicit Base2(int n) : n(n) {}
    virtual ~Base2() = default;
    void f() {
        std::cout << "Base" << std::endl;
    }
    int32_t n = 0;
    int32_t n2 = 2;
};

// 虚继承会使用一张虚表记录基类的偏移，因此会增加一个虚表指针
class D1: virtual public Base, virtual public Base2
{
public:
    D1() : Base(1), Base2(2) {}
    virtual ~D1() = default;
    void fd1() {}
};


class D2: virtual public Base
{
public:
    D2() : Base(2) {}
    void fd2() {}
};

class DD: public D1, public D2
{
public:
    DD() : Base(2) , Base2(2){}
    void fdd() {}
};

int main()
{
    std::string str = "abc";
    std::vector<int> vec{1, 2, 3, 4};

    std::cout << "string size: " << sizeof(str) << std::endl;
    std::cout << "vector<int> size: " << sizeof(vec) <<std::endl;

    std::shared_ptr<int> sp1 = std::make_shared<int>(1);
    std::shared_ptr<int> sp2(new int(2));
    std::weak_ptr<int> wp = sp1;
    std::shared_ptr<int> sp3(new int(3), [](int* pp){
        delete pp;
    });

    struct upDeleter
    {
        void operator()(int* n)
        {
            std::cout << "upDeleter: " << *n << std::endl;
            delete n;
        }
    };

    auto lambdaP = [](int* p){ std::cout << "lambdaP: " << *p << std::endl; delete p; };
    std::cout << "std::shared_ptr<int> size: " << sizeof(sp1) << std::endl;
    std::cout << "std::weak_ptr<int> size: " << sizeof(wp) <<std::endl;
    std::cout << "std::unique_ptr<int> size: " << sizeof(std::unique_ptr<int>) << std::endl;
    std::cout << "std::unique_ptr<int, void(*)(int*)> size: " << sizeof(std::unique_ptr<int, void(*)(int*)>) <<std::endl;
    std::cout << "std::unique_ptr<int, std::function<void(int*)>> size: " << sizeof(std::unique_ptr<int, std::function<void(int*)>>) <<std::endl;
    std::cout << "std::unique_ptr<int, decltype(lambdaP)> size: " << sizeof(std::unique_ptr<int, decltype(lambdaP)>) <<std::endl;
    std::cout << "std::unique_ptr<int, upDeleter> size: " << sizeof(std::unique_ptr<int, upDeleter>) <<std::endl;

    {
        std::unique_ptr<int, std::function<void(int*)>> up11(new int(11), upDeleter());
        std::unique_ptr<int, std::function<void(int*)>> up12(new int(12), lambdaP);
        std::unique_ptr<int, decltype(lambdaP)> up2{new int(2), lambdaP};
        std::unique_ptr<int, upDeleter> up3(new int{3});
    }

    A a;

    auto spA = std::shared_ptr<A>(new A);
    auto spA2 = spA.get()->shared_from_this();

    std::variant<int32_t, float> variant1;
    std::variant<int32_t, double> variant2;
    std::variant<int32_t, double, std::string> variant3;
    variant3 = "abcd";
    std::get<2>(variant3) = "aaaaaaaaaaaa";
    std::cout << "Variant3: " << std::get<std::string>(variant3) << std::endl;

    std::cout << "variant<int32_t, float> size: " << sizeof(variant1) << std::endl;
    std::cout << "variant<int32_t, double> size: " << sizeof(variant2) <<std::endl;
    std::cout << "variant<int32_t, double, std::string> size: " << sizeof(variant3) << std::endl;

    std::optional<bool> optionalBool;
    std::optional<int> optionalInt;
    std::optional<std::string> optionalString;
    std::cout << "std::optional<bool> size: " << sizeof(optionalBool) << std::endl;
    std::cout << "std::optional<int> size: " << sizeof(optionalInt) << std::endl;
    std::cout << "std::optional<std::string> size: " << sizeof(optionalString) <<std::endl;

    std::function<void(int)> function = [](int n){  std::cout << "function:" << n << std::endl; };
    std::function<void(int*, std::string)> function2;
    auto function3 = [&a](){ std::cout << "function3:" << a.n << std::endl; };
    std::cout << "std::function<void(int*)> size: " << sizeof(function) <<std::endl;
    std::cout << "std::function<void(int*, std::string)> size: " << sizeof(function2) <<std::endl;
    std::cout << "[a](){ } size: " << sizeof(function3) <<std::endl;

    auto function4 = std::move(function);
    if (function != nullptr)
    {
        function(1);
    }
    function4(2);


    std::cout << "\n------------Virtual Base class ---------------" << std::endl;
    DD dd;
    dd.fdd();
    std::cout << "DD size:" << sizeof(dd) << ", D1 Size:" << sizeof(D1) << ", D2 Size:" << sizeof(D2)<< std::endl;
    std::cout << "Base Size:" << sizeof(Base) << ", Base2 Size:" << sizeof(Base2) << std::endl;

    auto pb2n = &Base2::n;
    auto pb2n2 = &Base2::n2;
    std::cout << "&Base2::n:" << (*(int*)&pb2n) << std::endl;
    std::cout << "&Base2::n2:" << (*(int*)&pb2n2) << std::endl;

    return 0;
}